////这个函数更新时要运行一下ndk-build
////app\src\main>ndk-build
////如果增加了函数
////要用\app\src\main>javah -d jni -classpath ./com.rom.cpptest
////重新生成一下或者将鼠标放在新加的函数上，会有提示自动生成函数
#include <jni.h>
#include <string>
#include <fcntl.h>
#include "unistd.h"
#include <asm/unistd.h>
#include <android/log.h>
#define MAX_LINE 512
#define MAX_LENGTH 256
static const char *APPNAME = "MyReceiver";
#define LIBC "libc.so"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, APPNAME, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, APPNAME, __VA_ARGS__)
using namespace std;
#define __SYSCALL_LL_E(x) (x)
#define __SYSCALL_LL_O(x) (x)

#define __asm_syscall(...) do { \
	__asm__ __volatile__ ( "svc 0" \
	: "=r"(x0) : __VA_ARGS__ : "memory", "cc"); \
	return x0; \
	} while (0)

__attribute__((always_inline))
static inline long __syscall1(long n, long a)
{
    register long x8 __asm__("x8") = n;
    register long x0 __asm__("x0") = a;
    __asm_syscall("r"(x8), "0"(x0));
}

__attribute__((always_inline))
static inline long __syscall3(long n, long a, long b, long c)
{
    register long x8 __asm__("x8") = n;
    register long x0 __asm__("x0") = a;
    register long x1 __asm__("x1") = b;
    register long x2 __asm__("x2") = c;
    __asm_syscall("r"(x8), "0"(x0), "r"(x1), "r"(x2));
}

__attribute__((always_inline))
static inline long __syscall4(long n, long a, long b, long c, long d)
{
    register long x8 __asm__("x8") = n;
    register long x0 __asm__("x0") = a;
    register long x1 __asm__("x1") = b;
    register long x2 __asm__("x2") = c;
    register long x3 __asm__("x3") = d;
    __asm_syscall("r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3));
}
__attribute__((always_inline))
static inline int  my_openat(int __dir_fd, const void* __path, int __flags, int __mode ){
    return (int)__syscall4(__NR_openat, __dir_fd, (long)__path, __flags, __mode);
}

__attribute__((always_inline))
static inline ssize_t my_read(int __fd, void* __buf, size_t __count){
    return __syscall3(__NR_read, __fd, (long)__buf, (long)__count);
}

__attribute__((always_inline))
static inline int my_close(int __fd){
    return (int)__syscall1(__NR_close, __fd);
}

static inline int  add_inline(int a,int b ){
    return (int) a+b+1;
}

__attribute__((always_inline))
static inline bool  isRooted_use_svc_open( ){
    string a="/system";
    string b="bin";
    char infor[10];
    sprintf(infor,"/%s",b.c_str());
    string c="/su";
    string e=a+infor+c ;
    string d="/system/bin/su";

    int fd = my_openat(AT_FDCWD,e.c_str() , O_RDONLY | O_CLOEXEC, 0);
    if (fd > 0) {
        LOGI("root detect ");
        return true;
    } else
    {
        LOGI("root not detect ");
        return false;
    }
}

__attribute__((always_inline))
static inline bool  isRooted_use_libc_open( ){


    string d="/system/bin/su";
    int fd = open( d.c_str() , O_RDONLY | O_CLOEXEC );
    if (fd > 0) {
        LOGI("root detect in isRooted_use_libc_open");
        return true;
    } else
    {
        LOGI("root not detect ");
        return false;
    }
}
__attribute__((always_inline))
static inline string  get_cpuinfor_svc( ){


    string path="/proc/cpuinfo";
    //libc 调用
    // int fd = open( d.c_str() , O_RDONLY | O_CLOEXEC );
    // svc 调用
    long fd = my_openat(AT_FDCWD, path.c_str(), O_RDONLY | O_CLOEXEC, 0);

    if (fd > 0) {
        char buffer[8];
        memset(buffer, 0, 8);
        std::string str;
        //libc 调用
        //int fd = open(path, O_RDONLY);
        //失败 -1；成功：>0 读出的字节数  =0文件读完了
        while (my_read(fd, buffer, 1) != 0) {
            //LOGI("读取文件内容  %s" ,buffer);
            str.append(buffer);
        }
        my_close(fd);
        return str;
    } else
    {
        LOGI("%s not detect ",path.c_str());
        return "null";
    }
}

__attribute__((always_inline))
static  string  get_cpuinfor_libc( ){

    string d="/proc/cpuinfo";
    int fd = open( d.c_str() , O_RDONLY | O_CLOEXEC );
    if (fd > 0) {
        char buffer[1024];
        memset(buffer, 0, 1024);
        std::string str;
        while (read(fd, buffer, 1) != 0) {
            LOGI("读取文件内容  %s" ,buffer);
            str.append(buffer);
        }
        close(fd);
        return str;
    } else
    {
        LOGI("root not detect ");
        return "null";
    }
}

extern "C" JNIEXPORT jstring JNICALL
Java_com_rom_cpptest_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++ 你好中国";
    int fd = my_openat(AT_FDCWD, "/system/bin/su", O_RDONLY | O_CLOEXEC, 0);
    if (fd > 0) {
        LOGI("root detect ");
    } else
    {
        LOGI("root not detect ");
    }
    return env->NewStringUTF(hello.c_str());
}


extern "C"
JNIEXPORT jint JNICALL
Java_com_rom_cpptest_MainActivity_add(JNIEnv *env, jobject thiz, jint a, jint b) {
    if(isRooted_use_libc_open())
    {
        LOGI("add函数中检测到root，可以进行上报，进行追封");
    }
    return  a+b;
}


extern "C"
JNIEXPORT jboolean JNICALL
Java_com_rom_cpptest_MainActivity_detectRoot_1svc(JNIEnv *env, jobject thiz) {

//    string ok="ok beging";
//    my_openat(0,0,0,0);
//    my_openat(0,0,0,0);
//    my_read(0,0,0);
//    my_read(0,0,0);
//    my_close(0);
//    my_close(0);
//    string end="end end";
    return isRooted_use_svc_open();
}

extern "C"
JNIEXPORT jboolean JNICALL
Java_com_rom_cpptest_MainActivity_detectRoot_1libC(JNIEnv *env, jobject thiz) {
    // TODO: implement detectRoot_libC()
    return isRooted_use_libc_open();
}


extern "C"
JNIEXPORT jstring JNICALL
Java_com_rom_cpptest_MainActivity_get_1cpuinfo_1svc(JNIEnv *env, jobject thiz) {
    // TODO: implement get_cpuinfo()
    return env->NewStringUTF(get_cpuinfor_svc().c_str());
}


extern "C"
JNIEXPORT jstring JNICALL
Java_com_rom_cpptest_MainActivity_get_1cpuinfo_1libc(JNIEnv *env, jobject thiz) {
    // TODO: implement get_cpuinfo_libc()
    return env->NewStringUTF(get_cpuinfor_libc().c_str());
}